var htmlType = 'text/html';
var jsonType = 'application/json';
var rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
var scriptTypeRE = /^(?:text|application)\/javascript/i;
var xmlTypeRE = /^(?:text|application)\/xml/i;
var blankRE = /^\s*$/;
var class2type = {};
['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp', 'Object', 'Error'].forEach(function(name) {
	class2type["[object " + name + "]"] = name.toLowerCase();
})

var _type = function(obj) {
	return obj == null ? String(obj) : class2type[{}.toString.call(obj)] || "object";
};

var ajaxBeforeSend = function(xhr, settings) {
	var context = settings.context
	if (settings.beforeSend.call(context, xhr, settings) === false) {
		return false;
	}
};
var ajaxComplete = function(status, settings, xhr, data) {
	settings.complete.call(null, status, xhr, data);
};
var ajaxSuccess = function(data, xhr, settings) {
	settings.success.call(settings.context, data, 'success', xhr);
	ajaxComplete('success', settings, xhr, data);
};
var ajaxError = function(error, type, xhr, settings) {
	settings.error.call(settings, xhr, type, error);
	ajaxComplete('fail', settings, xhr, null);
};

var serialize = function(params, obj, traditional, scope) {
	var type, array = obj.isArray || obj instanceof Array,
		hash = typeof(obj) == 'object' && Object.getPrototypeOf(obj) === Object.prototype;
	for (let key in obj) {
		type = _type(obj[key]);
		if (scope) {
			key = traditional ? scope : scope + '[' + (hash || type === 'object' || type === 'array' ? key : '') + ']';
		}
		if (!scope && array) {
			params.add(obj[key].name, obj[key].value);
		} else if (type === "array" || (!traditional && type === "object")) {
			serialize(params, obj[key], traditional, key);
		} else {
			params.add(key, obj[key]);
		}
	}
};
var serializeData = function(options) {
	if (options.processData && options.data && typeof options.data !== "string") {
		var contentType = options.contentType;
		if (!contentType && options.headers) {
			contentType = options.headers['Content-Type'];
		}
		if (contentType && ~contentType.indexOf(jsonType)) { //application/json
			options.data = JSON.stringify(options.data);
		} else {
			options.data = httpx.param(options.data, options.traditional);
		}
	}
	if (options.data && (!options.type || options.type.toUpperCase() === 'GET')) {
		options.url = appendQuery(options.url, options.data);
		options.data = undefined;
	}
};
var appendQuery = function(url, query) {
	if (query === '') {
		return url;
	}
	return (url + '&' + query).replace(/[&?]{1,2}/, '?');
};
var mimeToDataType = function(mime) {
	if (mime) {
		mime = mime.split(';', 2)[0];
	}
	return mime && (mime === htmlType ? 'html' :
		mime === jsonType ? 'json' :
		scriptTypeRE.test(mime) ? 'script' :
		xmlTypeRE.test(mime) && 'xml') || 'text';
};

var httpx = {};
httpx.noop = function() {};

httpx.ajaxSettings = {
	type: 'GET',
	beforeSend: httpx.noop,
	success: httpx.noop,
	error: httpx.noop,
	complete: httpx.noop,
	context: null,
	xhr: function(settings) {
		if (window.plus && window.plus.net) {
			if (settings.crossDomain) { //强制使用plus跨域
				return new plus.net.XMLHttpRequest();
			}
			//仅在webview的url为远程文件，且ajax请求的资源不同源下使用plus.net.XMLHttpRequest
			var originAnchor = document.createElement('a');
			originAnchor.href = window.location.href;
			if (originAnchor.protocol !== 'file:') {
				var urlAnchor = document.createElement('a');
				urlAnchor.href = settings.url;
				urlAnchor.href = urlAnchor.href;
				settings.crossDomain = (originAnchor.protocol + '//' + originAnchor.host) !== (urlAnchor.protocol + '//' +
					urlAnchor.host);
				if (settings.crossDomain) {
					return new plus.net.XMLHttpRequest();
				}
			}
			if (window.webkit && window.webkit.messageHandlers) { //wkwebview下同样使用5+ xhr
				return new plus.net.XMLHttpRequest();
			}
		}
		return new window.XMLHttpRequest();
	},
	accepts: {
		script: 'text/javascript, application/javascript, application/x-javascript',
		json: jsonType,
		xml: 'application/xml, text/xml',
		html: htmlType,
		text: 'text/plain'
	},
	timeout: 0,
	processData: true,
	cache: false
}

httpx.now = function() {
	return Date.parse(new Date());
}

httpx.ajax = function(url, options) {
	if (typeof url === "object") {
		options = url;
		url = undefined;
	}
	var settings = options || {};
	settings.url = url || settings.url;
	for (var key in httpx.ajaxSettings) {
		if (settings[key] === undefined) {
			settings[key] = httpx.ajaxSettings[key];
		}
	}
	serializeData(settings);
	var dataType = settings.dataType;

	if (settings.cache === false || ((!options || options.cache !== true) && ('script' === dataType))) {
		settings.url = appendQuery(settings.url, '_=' + httpx.now());
	}
	var mime = settings.accepts[dataType && dataType.toLowerCase()];
	var headers = {};
	var setHeader = function(name, value) {
		headers[name.toLowerCase()] = [name, value];
	};
	var protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol;
	var xhr = settings.xhr(settings);
	var nativeSetHeader = xhr.setRequestHeader;
	var abortTimeout;

	setHeader('Accept', mime || '*/*');
	if (!!(mime = settings.mimeType || mime)) {
		if (mime.indexOf(',') > -1) {
			mime = mime.split(',', 2)[0];
		}
		xhr.overrideMimeType && xhr.overrideMimeType(mime);
	}
	if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() !== 'GET')) {
		setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded');
	}
	if (settings.headers) {
		for (var name in settings.headers)
			setHeader(name, settings.headers[name]);
	}
	xhr.setRequestHeader = setHeader;

	xhr.onreadystatechange = function() {
		if (xhr.readyState === 4) {
			xhr.onreadystatechange = httpx.noop;
			clearTimeout(abortTimeout);
			var result, error = false;
			var isLocal = protocol === 'file:';
			if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304 || (xhr.status === 0 && isLocal && xhr.responseText)) {
				dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type'));
				result = xhr.responseText;

				try {
					if (dataType === 'script') {
						(1, eval)(result);
					} else if (dataType === 'xml') {
						result = xhr.responseXML;
					} else if (dataType === 'json') {
						result = blankRE.test(result) ? null : JSON.parse(result);
					}
				} catch (e) {
					error = e;
				}

				if (error) {
					ajaxError(error, 'parsererror', xhr, settings);
				} else {
					ajaxSuccess(result, xhr, settings);
				}
			} else {
				var status = xhr.status ? 'error' : 'abort';
				var statusText = xhr.statusText || null;
				if (isLocal) {
					status = 'error';
					statusText = '404';
				}
				ajaxError(statusText, status, xhr, settings);
			}
		}
	};
	if (ajaxBeforeSend(xhr, settings) === false) {
		xhr.abort();
		ajaxError(null, 'abort', xhr, settings);
		return xhr;
	}

	if (settings.xhrFields) {
		for (var name in settings.xhrFields) {
			xhr[name] = settings.xhrFields[name];
		}
	}

	var async = 'async' in settings ? settings.async : true;

	xhr.open(settings.type.toUpperCase(), settings.url, async, settings.username, settings.password);

	for (var name in headers) {
		if (headers.hasOwnProperty(name)) {
			nativeSetHeader.apply(xhr, headers[name]);
		}
	}
	if (settings.timeout > 0) {
		abortTimeout = setTimeout(function() {
			xhr.onreadystatechange = httpx.noop;
			xhr.abort();
			ajaxError(null, 'timeout', xhr, settings);
		}, settings.timeout);
	}
	xhr.send(settings.data ? settings.data : null);
	return xhr;
};

httpx.param = function(obj, traditional) {
	var params = [];
	params.add = function(k, v) {
		this.push(encodeURIComponent(k) + '=' + encodeURIComponent(v));
	};
	serialize(params, obj, traditional);
	return params.join('&').replace(/%20/g, '+');
};


//验证表单
function checkRule(data, rule) {
	for (var i = 0; i < rule.length; i++) {
		if (!rule[i].name) {
			return [true, '']
		}
		if (!rule[i].error) {
			return [true, '']
		}
		if (!rule[i].check) {
			return [true, '']
		}
		if (!data[rule[i].name]) {
			return [false, rule[i].error]
		}
		switch (rule[i].check) {
			case 'string':
				var reg = new RegExp('^.{' + rule[i].rule + '}$');
				if (!reg.test(data[rule[i].name])) {
					return [false, rule[i].error]
				}
				break;
			case 'int':
				var reg = new RegExp('^(-[1-9]|[1-9])[0-9]{' + rule[i].rule + '}$');
				if (!reg.test(data[rule[i].name])) {
					return [false, rule[i].error]
				}
				break;
				break;
			case 'between':
				if (Number(data[rule[i].name]) == NaN) {
					return [false, rule[i].error]
				}
				var minMax = rule[i].rule.split(',');
				minMax[0] = Number(minMax[0]);
				minMax[1] = Number(minMax[1]);
				if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) {
					return [false, rule[i].error]
				}
				break;
			case 'betweenD':
				var reg = /^-?[1-9][0-9]?$/;
				if (!reg.test(data[rule[i].name])) {
					return [false, rule[i].error]
				}
				var minMax = rule[i].rule.split(',');
				minMax[0] = Number(minMax[0]);
				minMax[1] = Number(minMax[1]);
				if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) {
					return [false, rule[i].error]
				}
				break;
			case 'betweenF':
				var reg = /^-?[0-9][0-9]?.+[0-9]+$/;
				if (!reg.test(data[rule[i].name])) {
					return [false, rule[i].error]
				}
				var minMax = rule[i].rule.split(',');
				minMax[0] = Number(minMax[0]);
				minMax[1] = Number(minMax[1]);
				if (data[rule[i].name] > minMax[1] || data[rule[i].name] < minMax[0]) {
					return [false, rule[i].error]
				}
				break;
			case 'same':
				if (data[rule[i].name] != rule[i].rule) {
					return [false, rule[i].error]
				}
				break;
			case 'notsame':
				if (data[rule[i].name] == rule[i].rule) {
					return [false, rule[i].error]
				}
				break;
			case 'email':
				var reg = /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
				if (!reg.test(data[rule[i].name])) {
					return [false, rule[i].error]
				}
				break;
			case 'phoneno':
				var reg = /^1[0-9]{10,10}$/;
				if (!reg.test(data[rule[i].name])) {
					return [false, rule[i].error]
				}
				break;
			case 'zipcode':
				var reg = /^[0-9]{6}$/;
				if (!reg.test(data[rule[i].name])) {
					return [false, rule[i].error]
				}
				break;
			case 'reg':
				var reg = new RegExp(rule[i].rule);
				if (!reg.test(data[rule[i].name])) {
					return [false, rule[i].error]
				}
				break;
			case 'in':
				if (rule[i].rule.indexOf(data[rule[i].name]) == -1) {
					return [false, rule[i].error]
				}
				break;
			case 'notnull':
				if (data[rule[i].name] == null || data[rule[i].name].length < 1) {
					return [false, rule[i].error]
				}
				break;
		}
	}
	return [true, '']
}


const svcInvoke = {
	install(Vue, initurl, option) {
		svcInvoke.config.baseUrl = initurl;
		svcInvoke.option = Object.assign({}, option);
		Vue.prototype.$get = svcInvoke.get;
		Vue.prototype.$put = svcInvoke.put;
		Vue.prototype.$del = svcInvoke.del;
		Vue.prototype.$post = svcInvoke.post;
		Vue.prototype.$save = svcInvoke.save;
		Vue.prototype.$request = svcInvoke.request;
		Vue.prototype.$svcInvoke = svcInvoke;
		Vue.prototype.$http      = httpx.ajax;
	},
	cache : {},
	option: {},
	config: {
		_token: '',
		baseUrl: '',
		headers: {
			"content-type": "application/x-www-form-urlencoded"
		},
		dataType: "json",
		responseType: "text"
	},
	setConf(key, val) {
		if (key) {
			svcInvoke.config[key] = val || null;
		}
	},
	request(uri, options) {
		return new Promise((resolve, reject) => {
			//表单验证
			if (options.data instanceof Array) {
				if (options.data.length > 1) {
					let check = checkRule(options.data[0], options.data[1])
					console.log(check);
					if (!check[0]) {
						return resolve({
							code: 1,
							msg: check[1]
						});
					}
				}
				options.data = options.data[0];
			}

			options.complete = (status, response, data) => {
				// 接口请求成功
				if (response.status == 200) {
					if( options.data && options.data._cache ){
						svcInvoke.cache[uri] = data;
					}
					return resolve(data);
				} else {
					return reject(response);
				}
			}


			if( options.data && options.data._cache && svcInvoke.cache[uri] ){
				return resolve(svcInvoke.cache[uri]);
			}
			
			let url = uri;
			if (svcInvoke.config._token) {
				if (uri.indexOf('?') != '-1') {
					url = uri + '&access-token=' + svcInvoke.config._token;
				} else {
					url = uri + '?access-token=' + svcInvoke.config._token;
				}
				//options.data = Object.assign({},options.data,{access_token:svcInvoke.config._token});
			}

			// 开始请求
			httpx.ajax(svcInvoke.config.baseUrl + url, Object.assign({}, svcInvoke.config, options))
		});
	},
	get(url, data, options) {
		if (!options) {
			options = {}
		}
		options.data = data
		options.type = 'GET'
		return svcInvoke.request(url, options)
	},
	post(url, data, options) {
		if (!options) {
			options = {}
		}
		options.data = data
		options.type = 'POST'
		return svcInvoke.request(url, options)
	},
	put(url, data, options) {
		if (!options) {
			options = {}
		}
		options.type = 'POST';
		options.data = Object.assign({}, data, {
			_method: 'PUT'
		});
		return svcInvoke.request(url, options)
	},
	del(url, data, options) {
		if (!options) {
			options = {}
		}
		options.type = 'POST';
		options.data = Object.assign({}, data, {
			_method: 'DELETE'
		});
		return svcInvoke.request(url, options)
	},
	save(url, data, options) {
		if (data.id) {
			return svcInvoke.put(url + '/' + data.id, data, options);
		} else {
			return svcInvoke.post(url, data, options);
		}
	}
}

export default svcInvoke;
